home *** CD-ROM | disk | FTP | other *** search
/ Developer CD Series 1997 May: Tool Chest / Dev.CD May 97 TC.toast / Sample Code / Snippets / Development Tools & Languages / Long doubles w⁄MathLib / long_double.c < prev    next >
Encoding:
C/C++ Source or Header  |  1996-11-15  |  5.5 KB  |  154 lines  |  [TEXT/CWIE]

  1. /*
  2. **    Apple Macintosh Developer Technical Support
  3. **
  4. **    Routine demonstrating how to call MathLib functions that use 128 bit
  5. **    long doubles as arguments and return values.
  6. **
  7. **    by Mark Cookson, Apple Developer Technical Support
  8. **
  9. **    File:    long_double.c
  10. **
  11. **    Copyright ©1996 Apple Computer, Inc.
  12. **    All rights reserved.
  13. **
  14. **    You may incorporate this sample code into your applications without
  15. **    restriction, though the sample code has been provided "AS IS" and the
  16. **    responsibility for its operation is 100% yours.  However, what you are
  17. **    not permitted to do is to redistribute the source as "Apple Sample
  18. **    Code" after having made changes. If you're going to re-distribute the
  19. **    source, we require that you make it clear in the source that the code
  20. **    was descended from Apple Sample Code, but that you've made changes.
  21. */
  22.  
  23. /*
  24.     This is for PowerPC only, and the assembly code at the end is PowerPC
  25.     assembly.  The MathLib library is a PowerPC only library.
  26.  
  27.     This code has been tested with Metrowerks Codewarrior 10 and produces
  28.     the same result as standard code compiled with Mr. C (with the 128 bit
  29.     long double option turned on).
  30.  
  31.     This code is needed to call the MathLib functions because the current
  32.     Metrowerks compilers do not create a 128 bit long double, they create
  33.     a 64 bit long double.  All of the MathLib functions that require a long
  34.     double expect a 128 bit long double and therefore do not produce the
  35.     correct results when given a 64 bit long double.
  36.  
  37.     The callMathLib1ArgFcn routine takes three pointers, two pointers to
  38.     long_doubles and one ProcPtr.  The first pointer to a long_double is
  39.     the argument, the second pointer to a long_double is the result, and
  40.     the ProcPtr is the MathLib function to be called.
  41.  
  42.     The callMathLib2ArgFcn routine takes four pointers, three pointers to
  43.     long_doubles and one ProcPtr.  The first two pointers to long_double's
  44.     are the first two arguments to the function to be called, the third pointer
  45.     to a long_double is the result returned by the function to be called, and
  46.     the ProcPtr is the MathLib function to be called (in this example the powl
  47.     function).
  48.  
  49.     The callMathLibXArgFcn functions set up the floating point registers,
  50.     call the MathLib function, and then return the results in the result
  51.     structure.
  52.  
  53.     The callMathLibFcn can easily be modified to deal with other functions
  54.     which don't take only long doubles or return something other than a
  55.     long double, but that is left up to the reader.
  56.  
  57.     There are only 5 out of 46 functions in fp.h that these two routines
  58.     don't cover.
  59. */
  60.  
  61. #include <stdio.h>
  62. #include <fp.h>
  63.  
  64. //what a real long double (double-double) looks like
  65. typedef struct long_double {
  66.     double    head;
  67.     double    tail;
  68. } long_double;
  69.  
  70. //prototype for functions which will call the passed MathLib function the correct way
  71. //this function can work for any function that takes one long double and returns a long double
  72. asm void callMathLib1ArgFcn ( ProcPtr fcn, long_double *x, long_double *res );
  73.  
  74. //this function can work for any function that takes two long doubles and returns a long double
  75. asm void callMathLib2ArgFcn ( ProcPtr fcn, long_double *x, long_double *y, long_double *res );
  76.  
  77. void main (void) {
  78.     long_double    x,
  79.                 y,
  80.                 ldResult;
  81.     double        dResult;
  82.  
  83.     x.head = 3.141592653;
  84.     x.tail = 0.0;
  85.     y.head = 5.0;
  86.     y.tail = 0.0;
  87.     ldResult.head = 0.0;
  88.     ldResult.tail = 0.0;
  89.  
  90.     callMathLib2ArgFcn ((ProcPtr)powl, &x, &y, &ldResult);
  91.  
  92.     //this is the correct conversion from a long double to a double
  93.     //See page 5-7 of Inside Macintosh:PowerPC Numerics
  94.     dResult = ldResult.head + ldResult.tail;
  95.  
  96.     printf ("The head is: %1.17e\nThe tail is: %1.17e\n", ldResult.head, ldResult.tail);
  97.     printf ("The value of ldResult converted to a double is: %1.17e\n", dResult);
  98. }
  99.  
  100. //This is PowerPC assembly for calling the PowerPC-only MathLib library.
  101. //These functions do the dirty work of setting things up for the call to the MathLib function.
  102. //This code is for ease of reading, not for speed.
  103. asm void callMathLib1ArgFcn ( ProcPtr fcn, long_double *x, long_double *res ) {
  104.         fralloc                    //create a stack frame because we will be calling other functions
  105.  
  106.         lwz        r8,x            //put pointer to argument into register
  107.  
  108.         lfd        fp1,0(r8)        //put the real arguments in the fp registers
  109.         lfd        fp2,8(r8)
  110.  
  111.         lwz        r12,fcn            //put the address of the function to call in r12
  112.         stw        RTOC,20(SP)        //setup the stack for the call
  113.         lwz        r0,0(r12)
  114.         lwz        RTOC,4(r12)
  115.         mtctr    r0
  116.         bctrl                    //call the MathLib function
  117.         lwz        RTOC,20(SP)        //restore our RTOC
  118.  
  119.         lwz        r10,res            //return our results in the res structure
  120.         stfd    fp1,0(r10)        //this is the head of the result
  121.         stfd    fp2,8(r10)        //this is the tail of the result
  122.  
  123.         frfree                    //clean up stack frame
  124.         blr                        //back from whence we came
  125. }
  126.  
  127. asm void callMathLib2ArgFcn ( ProcPtr fcn, long_double *x, long_double *y, long_double *res ) {
  128.         fralloc                    //create a stack frame because we will be calling other functions
  129.  
  130.         lwz        r8,x            //put pointers to arguments into registers
  131.         lwz        r9,y
  132.  
  133.         lfd        fp1,0(r8)        //put the real arguments in the fp registers
  134.         lfd        fp2,8(r8)
  135.         lfd        fp3,0(r9)
  136.         lfd        fp4,8(r9)
  137.  
  138.         lwz        r12,fcn            //put the address of the function to call in r12
  139.         stw        RTOC,20(SP)        //setup the stack for the call
  140.         lwz        r0,0(r12)
  141.         lwz        RTOC,4(r12)
  142.         mtctr    r0
  143.         bctrl                    //call the MathLib function
  144.         lwz        RTOC,20(SP)        //restore our RTOC
  145.  
  146.         lwz        r10,res            //return our results in the res structure
  147.         stfd    fp1,0(r10)        //this is the head of the result
  148.         stfd    fp2,8(r10)        //this is the tail of the result
  149.  
  150.         frfree                    //clean up stack frame
  151.         blr                        //back from whence we came
  152. }
  153.  
  154.